home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / games / mosaic / part01 / mosaic.c next >
C/C++ Source or Header  |  1991-07-30  |  20KB  |  937 lines

  1. /*
  2.  *  mosaic.c
  3.  *  X version by kirk johnson  october 1990
  4.  *  Amiga version by Loren J. Rittle  Sun Feb 24 06:17:30 1991
  5.  *  Aris, this ones for you...
  6.  *        ...when do I get my pizza :-)
  7.  *
  8.  *  It only took 4-5 hours to port from X, I did it on a dare!
  9.  *  No Copyright N(c) 1991 Loren J. Rittle.  No rights reserved.
  10.  *  Some code generated via PowerWindows 2.5.
  11.  *  I also used their PD event shell as a starting point.
  12.  *  
  13.  *  Original UseNet post header:
  14.  *  Path: news.larc.nasa.gov!elroy.jpl.nasa.gov!usc!cs.utexas.edu!sun-barr!newstop!exodus!kanchenjunga.LCS.MIT.EDU
  15.  *  From: tuna@kanchenjunga.LCS.MIT.EDU (Kirk 'UhOh' Johnson)
  16.  *  Newsgroups: comp.sources.x
  17.  *  Subject: v11i083: mosaic, Part01/01
  18.  *  Message-ID: <8101@exodus.Eng.Sun.COM>
  19.  *  Date: 17 Feb 91 19:12:47 GMT
  20.  *  Sender: news@exodus.Eng.Sun.COM
  21.  *  Lines: 2409
  22.  *  Approved: argv@sun.com
  23.  *  
  24.  *  Submitted-by: tuna@kanchenjunga.LCS.MIT.EDU (Kirk 'UhOh' Johnson)
  25.  *  Posting-number: Volume 11, Issue 83
  26.  *  Archive-name: mosaic/part01
  27.  *
  28.  *  Thanks to Kirk for releasing such a nice simple game program with source...
  29.  *  Hard Drive Installable and Multitasks, thus better than any psygnosis game...
  30.  */
  31.  
  32. #include <exec/types.h>
  33. #include <exec/io.h>
  34. #include <exec/memory.h>
  35. #include <libraries/dos.h>
  36. #include <intuition/intuition.h>
  37. #include <graphics/gfxmacros.h>
  38. #include <proto/all.h>
  39. /*#include <stdlib.h>*/
  40. #include <time.h>
  41. #include <math.h>
  42. #include <string.h>
  43. #include "mosaic.h"
  44.  
  45. /* modified repel distance from mouse Mar '91 (SO) */
  46. #define X_OFF 36 /*27 */
  47. #define Y_OFF 23 /*17 */
  48.  
  49. #undef _main
  50. void    _main(void);
  51.  
  52. struct IntuitionBase *IntuitionBase = NULL;
  53. struct GfxBase *GfxBase = NULL;
  54.  
  55. SHORT BorderVectors1[] =
  56. {
  57.   0, 0,
  58.   65, 0,
  59.   65, 25,
  60.   0, 25,
  61.   0, 0
  62. };
  63.  
  64. struct Border Border1 =
  65. {
  66.   -1, -1,
  67.   3, 0, JAM1,
  68.   5,
  69.   BorderVectors1,
  70.   NULL
  71. };
  72.  
  73. struct IntuiText IText1 =
  74. {
  75.   3, 0, JAM2,
  76.   5, 7,
  77.   NULL,
  78.   "Restart",
  79.   NULL
  80. };
  81.  
  82. struct Gadget Gadget1 =
  83. {
  84.   NULL,
  85.   366, 107,
  86.   64, 24,
  87.   NULL,
  88.   RELVERIFY,
  89.   BOOLGADGET,
  90.   (APTR) & Border1,
  91.   NULL,
  92.   &IText1,
  93.   NULL,
  94.   NULL,
  95.   NULL,
  96.   NULL
  97. };
  98.  
  99. struct IntuiText IText2 =
  100. {
  101.   3, 0, JAM2,
  102.   366, 138,
  103.   NULL,
  104.   "Next:",
  105.   NULL
  106. };
  107.  
  108. struct NewWindow NewWindowStructure1 =
  109. {
  110.   20, 10,
  111.   440, 188,
  112.   0, 1,
  113.   MOUSEBUTTONS + MOUSEMOVE + GADGETUP + CLOSEWINDOW + RAWKEY,
  114.   WINDOWDRAG + WINDOWDEPTH + REPORTMOUSE + WINDOWCLOSE + ACTIVATE + NOCAREREFRESH,
  115.   &Gadget1,
  116.   NULL,
  117.   "Mosaic, Amiga Version by Loren J. Rittle\0Sun Feb 24 04:36:18 1991",
  118.   NULL,
  119.   NULL,
  120.   450, 188,
  121.   450, 188,
  122.   WBENCHSCREEN
  123. };
  124.  
  125. struct NewWindow NewWindowStructure2 =
  126. {
  127.   465, 10,
  128.   170, 120,
  129.   0, 1,
  130.   NULL,
  131.   WINDOWDRAG + WINDOWDEPTH + NOCAREREFRESH,
  132.   NULL,
  133.   NULL,
  134.   "Mosaic Score",
  135.   NULL,
  136.   NULL,
  137.   450, 188,
  138.   450, 188,
  139.   WBENCHSCREEN
  140. };
  141.  
  142. char *ScoreFile = "mosaic.scores";
  143.  
  144. Word tile[NTiles];        /* the board */
  145. Word piece[NPieces];        /* the "deck" of pieces */
  146. Word nextpiece;            /* index into the deck */
  147.  
  148. Word size[NTiles];        /* score data structures */
  149. Word parent[NTiles];
  150.  
  151. Word tscore[3];            /* total score */
  152. Word pscore[3];            /* last piece score */
  153. Word remain[3];            /* tiles remaining */
  154.  
  155. static char buf[256];
  156.  
  157. NameAndScore highscore[NHighScores];
  158.  
  159. int highlitX = 0;
  160. int highlitY = 0;
  161.  
  162. int highlitXonDown;
  163. int highlitYonDown;
  164.  
  165. BPTR SpeakFH = NULL;
  166.  
  167. struct Window *wG = NULL;
  168. struct RastPort *rpG;
  169.  
  170. struct Window *wS = NULL;
  171. struct RastPort *rpS;
  172.  
  173. #define BoundVarVal(var, min, max) \
  174. {                                  \
  175.   if ((var) < (min))               \
  176.     (var) = (min);                 \
  177.   else if ((var) > (max))          \
  178.     (var) = (max);                 \
  179. }
  180.  
  181. UWORD chip backfill[8] =
  182. {0x1111, 0x4444, 0x1111, 0x4444, 0x1111, 0x4444, 0x1111, 0x4444};
  183.  
  184. UWORD chip solid[8] =
  185. {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
  186.  
  187. /* modified to _main Mar '91 (SO) */
  188. void _main()
  189. {
  190.   UWORD code;
  191.   ULONG class;
  192.   APTR object;
  193.   int MouseX, MouseY;
  194.   int x, y;
  195.  
  196.   struct IntuiMessage *message;
  197.  
  198.   IntuitionBase = OpenLibrary ("intuition.library", 0);
  199.   GfxBase = OpenLibrary ("graphics.library", 0);
  200.   if (!IntuitionBase || !GfxBase)
  201.     fatal ("Can't open Intuition and/or Graphics Library.");
  202.  
  203.   wG = OpenWindow (&NewWindowStructure1);
  204.   if (wG == NULL)
  205.     fatal ("Can't open a window.");
  206.   rpG = wG->RPort;
  207.  
  208.   wS = OpenWindow (&NewWindowStructure2);
  209.   if (wS == NULL)
  210.     fatal ("Can't open a window.");
  211.   rpS = wS->RPort;
  212.  
  213.   {
  214.     struct Process* proc = (struct Process *)FindTask(0L);
  215.     APTR temp = proc->pr_WindowPtr;
  216.  
  217.     proc->pr_WindowPtr = (APTR)-1L;
  218.     SpeakFH = Open ("speak:", MODE_NEWFILE);
  219.     proc->pr_WindowPtr = temp;
  220.   }
  221.  
  222.  
  223.   PrintIText (rpG, &IText2, 0, 0);
  224.  
  225.   ReadHighScores ();
  226.  
  227. restart:
  228.   InitGame ();
  229.   drawScore ();
  230.   SetAPen (rpG, 2);
  231.   SetAfPt (rpG, (void *) backfill, 3);
  232.   RectFill (rpG, 20, 14, 24 * 14 + 20, 24 * 7 + 14);
  233.  
  234.   SetAPen (rpG, 3);
  235.   for (x = 0; x < 25; x++)
  236.     {
  237.       Move (rpG, x * 14 + 20, 14);
  238.       Draw (rpG, x * 14 + 20, 24 * 7 + 14);
  239.     }
  240.  
  241.   for (y = 0; y < 25; y++)
  242.     {
  243.       Move (rpG, 20, y * 7 + 14);
  244.       Draw (rpG, 24 * 14 + 20, y * 7 + 14);
  245.     }
  246.  
  247.   while (1)
  248.     {
  249.       WaitPort (wG->UserPort);
  250.       while ((message = (struct IntuiMessage *) GetMsg (wG->UserPort)) != NULL)
  251.     {
  252.       code = message->Code;
  253.       object = message->IAddress;
  254.       class = message->Class;
  255.       MouseX = message->MouseX;
  256.       MouseY = message->MouseY;
  257.       ReplyMsg ((struct Message *) message);
  258.       if (class == CLOSEWINDOW)
  259.         QuitGame (0);
  260.       /*
  261.            * This is very kludgy, don't follow this example of how to read
  262.            * keys... This is a quick hack to allow the 'a' for auto play
  263.            * feature to work.  Try it, you may hate it! Because, the
  264.            * AutoPlay() function is not too smart.  LJR
  265.            */
  266.       if ((class == RAWKEY) && (code == 32))
  267.          AutoPlay ();
  268.       /* Here again, quick hack to support open/closing of
  269.        * score window via 's'.  LJR
  270.        */
  271.       if ((class == RAWKEY) && (code == 33))
  272.         {
  273.           if (wS == NULL)
  274.         {
  275.               wS = OpenWindow (&NewWindowStructure2);
  276.               if (wS == NULL)
  277.             fatal ("Can't open a window.");
  278.               rpS = wS->RPort;
  279.           drawScore ();
  280.         }
  281.           else
  282.         {
  283.           CloseWindow(wS);
  284.           wS = NULL;
  285.         }
  286.         }
  287.       if (class == MOUSEMOVE)
  288.         MoveBox (MouseX, MouseY);
  289.       if (class == MOUSEBUTTONS)
  290.         if (code & 0x0080)
  291.           {
  292.         if ((highlitXonDown == highlitX) &&
  293.             (highlitYonDown == highlitY))
  294.           {
  295.             if ((nextpiece < NPieces) &&
  296.             (DropPiece (highlitY, highlitX, piece[nextpiece])))
  297.               {
  298.             nextpiece += 1;
  299.             drawNext ();
  300.  
  301.             if (nextpiece == NPieces)
  302.               {
  303.                 MoveBox (-1, -1);
  304.                 CheckHighScore ();
  305.               }
  306.               }
  307.             else
  308.               if (SpeakFH)
  309.             Write (SpeakFH, "No Way!", 7);
  310.               else
  311.             DisplayBeep (NULL);
  312.           }
  313.         else
  314.           if (SpeakFH)
  315.             Write (SpeakFH, "Un-do!", 7);
  316.           else
  317.             DisplayBeep (NULL);
  318.           }
  319.         else
  320.           {
  321.         highlitXonDown = highlitX;
  322.         highlitYonDown = highlitY;
  323.           }
  324.       if ((class == GADGETUP) || (class == GADGETDOWN))
  325.         if (object == (void *) &Gadget1)
  326.           goto restart;
  327.     }
  328.     }
  329.  
  330. }
  331.  
  332. void
  333. MoveBox (int MouseX, int MouseY)
  334. {
  335.   int x, y;
  336.   int newX = (MouseX - X_OFF) / 14;
  337.   int newY = (MouseY - Y_OFF) / 7;
  338.  
  339.   BoundVarVal (newX, 0, 22);
  340.   BoundVarVal (newY, 0, 22);
  341.  
  342.   if ((newX == highlitX) && (newY == highlitY))
  343.     return;
  344.  
  345.   SetAPen (rpG, 3);
  346.   for (x = highlitX; x < highlitX + 3; x++)
  347.     {
  348.       Move (rpG, x * 14 + 20, highlitY * 7 + 14);
  349.       Draw (rpG, x * 14 + 20, highlitY * 7 + 14 + 14);
  350.     }
  351.  
  352.   for (y = highlitY; y < highlitY + 3; y++)
  353.     {
  354.       Move (rpG, highlitX * 14 + 20, y * 7 + 14);
  355.       Draw (rpG, highlitX * 14 + 20 + 28, y * 7 + 14);
  356.     }
  357.  
  358.   SetAfPt (rpG, (void *) backfill, 3);
  359.   SetAPen (rpG, 2);
  360.   if (!tile[highlitY * BoardSize + highlitX])
  361.     RectFill (rpG, highlitX * 14 + 21, highlitY * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+1) * 7 + 13);
  362.   if (!tile[highlitY * BoardSize + highlitX + 1])
  363.     RectFill (rpG, (highlitX+1) * 14 + 21, highlitY * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+1) * 7 + 13);
  364.   if (!tile[(highlitY + 1) * BoardSize + highlitX])
  365.     RectFill (rpG, highlitX * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+2) * 7 + 13);
  366.   if (!tile[(highlitY + 1) * BoardSize + highlitX + 1])
  367.     RectFill (rpG, (highlitX+1) * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+2) * 7 + 13);
  368.  
  369.   if (nextpiece == NPieces)
  370.     {
  371.       highlitX = highlitY = 0;
  372.       return;
  373.     }
  374.   highlitX = newX;
  375.   highlitY = newY;
  376.  
  377.   SetAPen (rpG, 1);
  378.   for (x = highlitX; x < highlitX + 3; x++)
  379.     {
  380.       Move (rpG, x * 14 + 20, highlitY * 7 + 14);
  381.       Draw (rpG, x * 14 + 20, highlitY * 7 + 14 + 14);
  382.     }
  383.  
  384.   for (y = highlitY; y < highlitY + 3; y++)
  385.     {
  386.       Move (rpG, highlitX * 14 + 20, y * 7 + 14);
  387.       Draw (rpG, highlitX * 14 + 20 + 28, y * 7 + 14);
  388.     }
  389.  
  390.   SetAfPt (rpG, (void *) solid, 3);
  391.   if (!tile[highlitY * BoardSize + highlitX])
  392.     {
  393.       SetAPen (rpG, piece[nextpiece] & 0x0003);
  394.       RectFill (rpG, highlitX * 14 + 21, highlitY * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+1) * 7 + 13);
  395.     }
  396.   if (!tile[highlitY * BoardSize + highlitX + 1])
  397.     {
  398.       SetAPen (rpG, (piece[nextpiece] & 0x000C)>>2);
  399.       RectFill (rpG, (highlitX+1) * 14 + 21, highlitY * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+1) * 7 + 13);
  400.     }
  401.   if (!tile[(highlitY + 1) * BoardSize + highlitX])
  402.     {
  403.       SetAPen (rpG, (piece[nextpiece] & 0x0030)>>4);
  404.       RectFill (rpG, highlitX * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+2) * 7 + 13);
  405.     }
  406.   if (!tile[(highlitY + 1) * BoardSize + highlitX + 1])
  407.     {
  408.       SetAPen (rpG, (piece[nextpiece] & 0x00C0)>>6);
  409.       RectFill (rpG, (highlitX+1) * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+2) * 7 + 13);
  410.     }
  411. }
  412.  
  413. void
  414. QuitGame (int rc)
  415. {
  416.   if (wG)
  417.     CloseWindow (wG);
  418.   if (wS)
  419.     CloseWindow (wS);
  420.   if (SpeakFH)
  421.     Close (SpeakFH);
  422.   if (GfxBase != NULL)
  423.     CloseLibrary (GfxBase);
  424.   if (IntuitionBase != NULL)
  425.     CloseLibrary (IntuitionBase);
  426.   exit (0);
  427. }
  428.  
  429. void
  430. warning (char *msg)
  431. {
  432. /* removed to be compatible with _main Mar '91 (SO)
  433.   fflush (stdout);
  434.   fprintf (stderr, "%s: warning! %s\n", AppName, msg);
  435.   fflush (stderr);
  436. */
  437. }
  438.  
  439. void
  440. fatal (char *msg)
  441. {
  442. /* removed to be compatible with _main Mar '91 (SO)
  443.   fflush (stdout);
  444.   fprintf (stderr, "%s: %s\n", AppName, msg);
  445. */
  446.   QuitGame (1);
  447. }
  448.  
  449. void
  450. ReadHighScores (void)
  451. {
  452.   int i;
  453.   FILE *s;
  454.  
  455.   s = fopen (ScoreFile, "r");
  456.   if (s == NULL)
  457.     {
  458.       warning ("unable to open score file; creating new one");
  459.  
  460.       for (i = 0; i < NHighScores; i++)
  461.     {
  462.       strcpy (highscore[i].uname, ".");
  463.       highscore[i].score = -1;
  464.     }
  465.  
  466.       WriteHighScores ();
  467.     }
  468.   else
  469.     {
  470.       for (i = 0; i < NHighScores; i++)
  471.     {
  472.       fgets (buf, 30, s);
  473.       if (sscanf (buf, "%s %d",
  474.               highscore[i].uname, &highscore[i].score) != 2)
  475.         fatal ("incomplete score file read");
  476.     }
  477.       fclose (s);
  478.     }
  479. }
  480.  
  481.  
  482. void
  483. WriteHighScores (void)
  484. {
  485.   int i;
  486.   FILE *s;
  487.  
  488.   s = fopen (ScoreFile, "w");
  489.   if (s == NULL)
  490.     fatal ("unable to open score file");
  491.  
  492.   for (i = 0; i < NHighScores; i++)
  493.     fprintf (s, "%s %d\n", highscore[i].uname, highscore[i].score);
  494.  
  495.   fclose (s);
  496. }
  497.  
  498. void
  499. CheckHighScore (void)
  500. {
  501.   int i;
  502.   int score;
  503.   char *uname;
  504.  
  505. static char name[24] = "Your Name Here";
  506.  
  507.   score = tscore[0] + tscore[1] + tscore[2];
  508.  
  509.   /*
  510.    * note that we don't actually try to do any locking of the high score
  511.    * file during this critical section ...
  512.    */
  513.  
  514.   ReadHighScores ();
  515.  
  516. /* (modified Mar '91 SO)
  517.     for (i = 0; i < NHighScores; i++)
  518.       if (strcmp (highscore[i].uname, uname) == 0)
  519.         break;
  520.  
  521.     if (i == NHighScores)
  522. */
  523.     i = NHighScores - 1;
  524.  
  525.   if (score > highscore[i].score)
  526.     {
  527.       while ((i > 0) && (score > highscore[i - 1].score))
  528.     {
  529.       strcpy (highscore[i].uname, highscore[i - 1].uname);
  530.       highscore[i].score = highscore[i - 1].score;
  531.       i -= 1;
  532.     }
  533.  
  534.   /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  535.    * user name for high score
  536.    *
  537.    * Added by Stephen Orr (SandIsoft) (Mar '91)
  538.    *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  539. {
  540. static struct StringInfo si = {name, NULL, 0, 24};
  541. static struct Gadget g = {NULL, 4, 2, 128, 9, GADGHCOMP, RELVERIFY|STRINGCENTER, STRGADGET, NULL, NULL, NULL, 0L, (APTR)&si, 0, NULL};
  542. static struct NewWindow nw = {100, 90, 140, 13, -1,-1, GADGETUP,SMART_REFRESH|ACTIVATE|RMBTRAP,&g,NULL,NULL,NULL,NULL,0,0,0,0,WBENCHSCREEN};
  543.  
  544. struct Window *win;
  545. struct Message *msg;
  546. int x;
  547.  
  548.     win = OpenWindow(&nw);
  549.     while (!ActivateGadget(&g, win, NULL));
  550.     Wait(1<<win->UserPort->mp_SigBit);
  551.     msg = GetMsg(win->UserPort);
  552.     ReplyMsg(msg);
  553.     CloseWindow(win);
  554.  
  555.     if (strlen(name)) uname = name;
  556.         else uname = "Anonymous";
  557.  
  558.     for (x=0;x<strlen(name);x++) if (name[x]==' ') name[x] = '_';
  559.  
  560. /* modified Mar '91 (SO)
  561.     uname = name;
  562.     uname = getenv ("USERNAME");
  563.     if (uname == NULL)
  564.     uname = "Unknown_Puzzle_Solver";
  565. */
  566. }
  567.  
  568.       strcpy (highscore[i].uname, uname);
  569.       highscore[i].score = score;
  570.  
  571.       WriteHighScores ();
  572.  
  573.       if (SpeakFH)
  574.     {
  575.       Write (SpeakFH, "Congratulations!", 16);
  576.       Write (SpeakFH, name, strlen(name)+1);
  577.       Write (SpeakFH, "You got a hi score.", 19);
  578.     }
  579.       else
  580.     DisplayBeep (NULL);
  581.     }
  582.   drawHighScores ();
  583. }
  584.  
  585. void
  586. AutoPlay (void)
  587. {
  588.   int r, c;
  589.  
  590.   while (nextpiece < NPieces)
  591.     {
  592.       do
  593.     {
  594.       r = rand () % (BoardSize - 1);
  595.       c = rand () % (BoardSize - 1);
  596.     }
  597.       while (!DropPiece (r, c, piece[nextpiece]));
  598.  
  599.       nextpiece += 1;
  600.       drawNext ();
  601.  
  602.       if (nextpiece == NPieces)
  603.     {
  604.       MoveBox (-1, -1);
  605.   drawHighScores ();
  606. /*      CheckHighScore (); */
  607.     }
  608.     }
  609. }
  610.  
  611. void
  612. UpdateAndScore (int r, int c, Word score[])
  613. {
  614.   int i;
  615.  
  616.   i = r * BoardSize + c;
  617.  
  618.   PossiblyMerge (i, i + 1);
  619.   PossiblyMerge (i + BoardSize, i + BoardSize + 1);
  620.  
  621.   PossiblyMerge (i, i + BoardSize);
  622.   PossiblyMerge (i + 1, i + BoardSize + 1);
  623.  
  624.   if (c >= 1)
  625.     {
  626.       PossiblyMerge (i, i - 1);
  627.       PossiblyMerge (i + BoardSize, i + BoardSize - 1);
  628.     }
  629.   if (r >= 1)
  630.     {
  631.       PossiblyMerge (i, i - BoardSize);
  632.       PossiblyMerge (i + 1, i - BoardSize + 1);
  633.     }
  634.   if (c <= (BoardSize - 3))
  635.     {
  636.       PossiblyMerge (i + 1, i + 2);
  637.       PossiblyMerge (i + BoardSize + 1, i + BoardSize + 2);
  638.     }
  639.   if (r <= (BoardSize - 3))
  640.     {
  641.       PossiblyMerge (i + BoardSize, i + (2 * BoardSize));
  642.       PossiblyMerge (i + BoardSize + 1, i + (2 * BoardSize) + 1);
  643.     }
  644.   /* compute the new score */
  645.   for (i = 0; i < 3; i++)
  646.     score[i] = 0;
  647.   for (i = 0; i < NTiles; i++)
  648.     if ((tile[i] != 0) && (parent[i] == i))
  649.       score[tile[i] - 1] += size[i] * size[i];
  650. }
  651.  
  652. void
  653. PossiblyMerge (int i, int j)
  654. {
  655.   Word irep;
  656.   Word jrep;
  657.   Word scan;
  658.  
  659.   /* tiles are not the same color */
  660.   if (tile[i] != tile[j])
  661.     return;
  662.  
  663.   /* find i's rep */
  664.   irep = i;
  665.   while (parent[irep] != irep)
  666.     irep = parent[irep];
  667.  
  668.   /* compress path from i to irep */
  669.   scan = i;
  670.   while (parent[scan] != scan)
  671.     {
  672.       scan = parent[scan];
  673.       parent[scan] = irep;
  674.     }
  675.  
  676.   /* find j's rep */
  677.   jrep = j;
  678.   while (parent[jrep] != jrep)
  679.     jrep = parent[jrep];
  680.  
  681.   /* compress path from j to jrep */
  682.   scan = j;
  683.   while (parent[scan] != scan)
  684.     {
  685.       scan = parent[scan];
  686.       parent[scan] = jrep;
  687.     }
  688.  
  689.   /* tiles are already in the same set */
  690.   if (irep == jrep)
  691.     return;
  692.  
  693.   /* merge the sets */
  694.   if (size[irep] > size[jrep])
  695.     {
  696.       parent[jrep] = irep;
  697.       size[irep] += size[jrep];
  698.     }
  699.   else
  700.     {
  701.       parent[irep] = jrep;
  702.       size[jrep] += size[irep];
  703.     }
  704. }
  705.  
  706. int
  707. DropPiece (int r, int c, Word p)
  708. {
  709.   int idx;
  710.   Word type;
  711.   Word nscore[3];
  712.  
  713.   idx = r * BoardSize + c;
  714.  
  715.   /* check for illegal move */
  716.   if ((tile[idx] != 0) ||
  717.       (tile[idx + 1] != 0) ||
  718.       (tile[idx + BoardSize] != 0) ||
  719.       (tile[idx + BoardSize + 1] != 0))
  720.     return 0;
  721.  
  722.   /* place the piece */
  723.   type = p & 0x03;
  724.   tile[idx] = type;
  725.   remain[type - 1] -= 1;
  726.   p >>= 2;
  727.  
  728.   type = p & 0x03;
  729.   tile[idx + 1] = type;
  730.   remain[type - 1] -= 1;
  731.   p >>= 2;
  732.  
  733.   type = p & 0x03;
  734.   tile[idx + BoardSize] = type;
  735.   remain[type - 1] -= 1;
  736.   p >>= 2;
  737.  
  738.   type = p & 0x03;
  739.   tile[idx + BoardSize + 1] = p & 0x03;
  740.   remain[type - 1] -= 1;
  741.  
  742.   /* update the score */
  743.   UpdateAndScore (r, c, nscore);
  744.   for (idx = 0; idx < 3; idx++)
  745.     {
  746.       pscore[idx] = nscore[idx] - tscore[idx];
  747.       tscore[idx] = nscore[idx];
  748.     }
  749.  
  750.   /* redraw */
  751.   drawTile (r++, c);
  752.   drawTile (r, c++);
  753.   drawTile (r--, c);
  754.   drawTile (r, c);
  755.   drawScore ();
  756.  
  757.   return 1;
  758. }
  759.  
  760. void
  761. InitGame (void)
  762. {
  763.   int i, j, k, l;
  764.   int idx, swap;
  765.  
  766.   /* randomize */
  767.   srand ((int) time (NULL));
  768.  
  769.   /* clear the board */
  770.   for (i = 0; i < NTiles; i++)
  771.     tile[i] = 0;
  772.  
  773.   /* set up deck */
  774.   idx = 0;
  775.   for (i = 1; i <= 3; i++)
  776.     for (j = 1; j <= 3; j++)
  777.       for (k = 1; k <= 3; k++)
  778.     for (l = 1; l <= 3; l++)
  779.       piece[idx++] = (i << 6) | (j << 4) | (k << 2) | (l << 0);
  780.  
  781.   /* shuffle */
  782.   for (i = 0; i < 1000; i++)
  783.     {
  784.       idx = rand () % NPieces;
  785.       swap = piece[idx];
  786.       piece[idx] = piece[0];
  787.       piece[0] = swap;
  788.     }
  789.   nextpiece = 0;
  790.  
  791.   /* clear score data structures */
  792.   for (i = 0; i < NTiles; i++)
  793.     {
  794.       size[i] = 1;
  795.       parent[i] = i;
  796.     }
  797.  
  798.   for (i = 0; i < 3; i++)
  799.     {
  800.       tscore[i] = 0;
  801.       pscore[i] = 0;
  802.       remain[i] = (NPieces * 4) / 3;
  803.     }
  804.   drawNext ();
  805. }
  806.  
  807. void
  808. drawTile (int r, int c)
  809. {
  810.   int x, y;
  811.  
  812.   x = c * 14 + 20;
  813.   y = r * 7 + 14;
  814.  
  815.   SetAfPt (rpG, (void *) solid, 3);
  816.   SetAPen (rpG, tile[r * BoardSize + c]);
  817.   RectFill (rpG, x + 1, y + 1, x + 13, y + 6);
  818. }
  819.  
  820. void
  821. drawHighScores (void)
  822. {
  823. static USHORT dither[] = {0x5555, 0xaaaa};
  824.  
  825.   int i;
  826.  
  827.   /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  828.    * dither background
  829.    *
  830.    * Added by Stephen Orr (SandIsoft) (Mar '91)
  831.    *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  832.   SetAPen(rpG,0);
  833.   SetAfPt(rpG, dither, 1);
  834.   SetDrMd(rpG, JAM1);
  835.   RectFill(rpG, 21, 15, 355, 181);
  836.   SetAfPt(rpG, NULL, 0);
  837.  
  838.   SetAPen (rpG, 1);
  839.   SetDrMd(rpG, JAM2);
  840.   for (i = 0; i < NHighScores; i++)
  841.     if (highscore[i].score > 0)
  842.       {
  843.     sprintf (buf, "%-24s %5d", highscore[i].uname, highscore[i].score);
  844.     Move (rpG, 50, 30 + i * 14);
  845.     Text (rpG, buf, strlen (buf));
  846.       }
  847. }
  848.  
  849. void
  850. drawNext (void)
  851. {
  852.   int p = (nextpiece < NPieces) ? piece[nextpiece] : 0;
  853.   int x = 26 * 14 + 20;
  854.   int y = 20 * 7 + 14;
  855.  
  856.   SetAfPt (rpG, (void *) solid, 3);
  857.   SetAPen (rpG, p & 0x03);
  858.   RectFill (rpG, x + 1, y + 1, x + 13, y + 6);
  859.   p >>= 2;
  860.   SetAPen (rpG, p & 0x03);
  861.   RectFill (rpG, x + 15, y + 1, x + 27, y + 6);
  862.   p >>= 2;
  863.   SetAPen (rpG, p & 0x03);
  864.   RectFill (rpG, x + 1, y + 8, x + 13, y + 13);
  865.   p >>= 2;
  866.   SetAPen (rpG, p & 0x03);
  867.   RectFill (rpG, x + 15, y + 8, x + 27, y + 13);
  868. }
  869.  
  870. void
  871. drawScore (void)
  872. {
  873.   int i, total, temp;
  874.  
  875.   if (!wS)
  876.     return;
  877.  
  878.   SetAPen(rpS, 3);
  879.   Move (rpS, 10, 20);
  880.   Text (rpS, "to play:", 8);
  881.  
  882.   Move (rpS, 10, 30);
  883.   for (i = 0; i < 3; i++)
  884.     {
  885.       SetAPen(rpS, i+1);
  886.       sprintf (buf, "%5d ", remain[i]);
  887.       Text (rpS, buf, strlen (buf));
  888.     }
  889.  
  890.   SetAPen(rpS, 3);
  891.   Move (rpS, 10, 50);
  892.   Text (rpS, "total:", 6);
  893.  
  894.   total = 0;
  895.   Move (rpS, 10, 60);
  896.   for (i = 0; i < 3; i++)
  897.     {
  898.       SetAPen(rpS, i+1);
  899.       total += tscore[i];
  900.       sprintf (buf, "%5d ", tscore[i]);
  901.       Text (rpS, buf, strlen (buf));
  902.     }
  903.  
  904.   /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  905.    * calculate yield
  906.    *
  907.    * Added by Stephen Orr (SandIsoft) (July '91)
  908.    *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  909.   temp = (34992 + remain[0]*remain[0] + remain[1]*remain[1] + remain[2]*remain[2]
  910.     - 2*(108*(remain[0]+remain[1]+remain[2])));
  911.   temp = temp?(100*total/temp):100;
  912.  
  913.   SetAPen(rpS, 3);
  914.   sprintf (buf, "%5.5d   Yeild %3.3d\%", total, temp);
  915.  
  916.   Move (rpS, 10, 70);
  917.   Text (rpS, buf, strlen (buf));
  918.  
  919.   Move (rpS, 10, 90);
  920.   Text (rpS, "piece:", 6);
  921.  
  922.   total = 0;
  923.   Move (rpS, 10, 100);
  924.   for (i = 0; i < 3; i++)
  925.     {
  926.       SetAPen(rpS, i+1);
  927.       total += pscore[i];
  928.       sprintf (buf, "%5d ", pscore[i]);
  929.       Text (rpS, buf, strlen (buf));
  930.     }
  931.  
  932.   SetAPen(rpS, 3);
  933.   sprintf (buf, "%5d", total);
  934.   Move (rpS, 10, 110);
  935.   Text (rpS, buf, strlen (buf));
  936. }
  937.